<template>
  <div class="menu">
    <div class="a-side">
      <div class="header">
        <div class="a-side-title">菜单管理</div>
        <div class="a-side-add" @click="handleEdit('add')">
          <i class="el-icon-circle-plus-outline"></i>
          <span>新增</span>
        </div>
      </div>
      <el-input
        v-model="filterText"
        placeholder="输入关键字进行过滤"
        size="small"
        clearable
        class="a-side-input"
      >
      </el-input>
      <el-tree
        ref="tree"
        v-loading="treeLoading"
        node-key="id"
        :data="menuTree"
        :default-expand-all="true"
        :filter-node-method="filterNode"
        :expand-on-click-node="false"
      >
        <span slot-scope="{ data }" class="custom-tree-node">
          <span class="node-label" @click="handleEdit('edit', data)">
            {{ data.name }}
          </span>
          <span>
            <el-button
              type="text"
              size="small"
              icon="el-icon-plus"
              @click="() => handleEdit('add', data)"
            >
            </el-button>
            <el-button
              type="text"
              size="small"
              icon="el-icon-delete"
              @click="() => handleRemove(data)"
            >
            </el-button>
          </span>
        </span>
      </el-tree>
    </div>
    <div v-if="showContent" class="content">
      <hzhy-form-renderer
        ref="formRender"
        label-position="right"
        label-width="100px"
        :content="content"
      >
        <el-button
          plain
          icon="el-icon-close"
          size="medium"
          :loading="submitLoading"
          class="mg-10"
          @click="clear"
        >
          取消
        </el-button>
        <el-button
          plain
          type="primary"
          size="medium"
          icon="el-icon-check"
          :loading="submitLoading"
          @click="handleSubmit"
        >
          确定
        </el-button>
      </hzhy-form-renderer>
    </div>
  </div>
</template>

<script>
import { listFormatTree, isPretty } from '@/utils'
import { APP_TYPE } from '@/const/system'
import * as api from '@/const/api'

export default {
  title: '资源管理',
  name: 'SystemMenu',
  data() {
    return {
      filterText: '',
      menuList: [],
      menuTree: [],
      treeLoading: false,
      content: [
        {
          $id: 'parentId',
          $type: 'select',
          label: '上级资源',
          $el: {
            placeholder: '上级资源',
            clearable: true,
            disabled: true,
          },
          $options: [],
        },
        {
          $id: 'name',
          $type: 'input',
          label: '资源名称',
          $el: {
            placeholder: '请输入资源名称',
            maxLength: 20,
            clearable: true,
          },
          rules: [{ required: true, message: '请输入资源名称', trigger: 'change' }],
        },
        {
          $id: 'appType',
          $type: 'select',
          label: '资源类型',
          $el: {
            placeholder: '请选择资源类型',
          },
          $options: APP_TYPE.options(),
          rules: [{ required: true, message: '请输入资源名称', trigger: 'change' }],
        },
        {
          $id: 'path',
          $type: 'input',
          label: '路由地址',
          hidden: (data) => {
            // 资源类型为菜单时显示
            return !(data.appType && data.appType === 'MENU')
          },
          $el: {
            placeholder: '请输入路由地址',
            maxLength: 200,
            clearable: true,
          },
        },
        {
          $id: 'url',
          $type: 'input',
          label: 'url',
          hidden: (data) => {
            // 资源类型为菜单时显示，可填写外部链接地址
            return !(data.appType && data.appType === 'MENU')
          },
          $el: {
            placeholder: '请输入url',
            maxLength: 200,
            clearable: true,
          },
        },
        {
          $id: 'component',
          $type: 'input',
          label: '前端组件',
          hidden: (data) => {
            // 资源类型为按钮时显示，可填写外部链接地址
            return !(data.appType && data.appType === 'BUTTON')
          },
          $el: {
            placeholder: '请输入前端组件',
            maxLength: 200,
            clearable: true,
          },
          rules: [{ required: true, message: '请输入前端组件', trigger: 'change' }],
        },
        {
          $id: 'urlPrefix',
          $type: 'input',
          label: 'urlPrefix',
          $el: {
            disabled: true,
          },
        },
        {
          $id: 'ordered',
          $type: 'input',
          label: '排序',
          $el: {
            type: 'number',
            placeholder: '请输入排序',
            maxLength: 20,
            clearable: true,
          },
        },
        {
          $id: 'valid',
          $type: 'switch',
          label: '启用标志',
          $el: {
            activeValue: 1,
            inactiveValue: 0,
          },
        },
      ],
      submitLoading: false, // 提交加载标识
      showContent: false, // 是否显示表单
      currentRow: {}, // 当前选中项
    }
  },
  computed: {
    // 编辑还是新增
    isEdit() {
      return !!this.currentRow.id
    },
    // 根据权限判断是否显示确认按钮
    surePermission() {
      if (this.isEdit) {
        return this.$ac.access('/system/menu_edit')
      }
      return true
    },
  },
  watch: {
    filterText(val) {
      this.$refs.tree.filter(val)
    },
  },
  mounted() {
    this.goPage()
  },
  methods: {
    // 页面加载
    async goPage() {
      this.treeLoading = true
      try {
        const { code, msg, data } = await this.$axios.$get(api.sysAppList)
        if (+code !== 200) {
          throw new Error(msg || '操作失败')
        }
        // 菜单树状结构
        this.menuTree = listFormatTree(data, {
          sort: 'ordered',
          parentId: 0,
          pid: '0',
        })
        // 菜单list结构
        this.menuList = data.map(({ name, id }) => ({
          label: name,
          value: id,
        }))
        // 设置上级菜单数据
        this.$set(this.content[0], '$options', this.menuList)
        this.clear() // 清除表单数据
        this.filterText = ''
      } catch (err) {
        this.$message.error(err.message)
      } finally {
        this.treeLoading = false
      }
    },
    handleEdit(type, row) {
      // 按钮不允许添加子级
      if (type === 'add' && row && row.appType === 'BUTTON') {
        this.$message.error('按钮不允许添加子级')
        return
      }

      this.showContent = true

      if (type === 'add') {
        this.currentRow = {}
        this.$refs.formRender && this.$refs.formRender.resetFields()

        const defautForm = {
          valid: 1,
          ordered: 0,
        }
        // 有父级，添加父级参数
        if (row) {
          defautForm.parentId = row.id
          defautForm.urlPrefix = row.path
        }

        this.$nextTick(() => {
          this.$refs.formRender.updateForm({ ...defautForm }) // 设置默认值
        })
        return
      }
      this.currentRow = row
      this.$nextTick(() => {
        this.$refs.formRender.updateForm({
          ...row,
          parentId: row.parentId || '',
        })
      })
    },
    async handleRemove(row) {
      try {
        if (isPretty(row.children)) {
          throw new Error('当前菜单下有子菜单不能删除')
        }

        const isFlag = await this.$confirm('确认删除？', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning',
        })
        if (isFlag !== 'confirm') {
          return
        }
        this.treeLoading = true
        const { code, msg } = await this.$axios.$delete(api.sysApp, {
          params: {
            id: row.id,
          },
        })
        if (+code !== 200) {
          throw new Error(msg || '操作失败')
        }
        this.$message.success('操作成功')
        this.goPage() // 刷新界面
      } catch (err) {
        err.message && this.$message.error(err.message)
      } finally {
        this.treeLoading = false
      }
    },
    async handleSubmit() {
      try {
        // 表单校验
        const valid = await this.$refs.formRender.validate()
        // 校验失败或者onConfirm不存在直接返回
        if (!valid) {
          return
        }

        // 获取表单值
        const formData = this.$refs.formRender.getFormValue()

        const params = {
          parentId: 0, // 默认值为0
          ...formData,
        }
        // 根据资源类型过滤数据
        if (params.appType === 'BUTTON') {
          params.path = ''
          params.url = ''
        } else {
          params.component = ''
        }

        if (this.isEdit) {
          // 编辑需要加上id参数
          params.id = this.currentRow.id
        }

        this.submitLoading = true

        let res = ''

        if (this.isEdit) {
          res = await this.$axios.$put(api.sysApp, params)
        } else {
          res = await this.$axios.$post(api.sysApp, params)
        }

        const { code, msg } = res
        if (+code !== 200) {
          throw new Error(msg || '操作失败')
        }

        this.$message.success('操作成功')
        this.goPage() // 刷新界面
      } catch (err) {
        err.message && this.$message.error(err.message)
      } finally {
        this.submitLoading = false
      }
    },
    // 清除表单数据
    clear() {
      this.currentRow = {}
      this.$refs.formRender && this.$refs.formRender.resetFields()
      this.showContent = false
    },
    filterNode(value, data) {
      if (!value) {
        return true
      }
      return data.name.includes(value)
    },
  },
}
</script>

<style lang="less" scoped>
@import '~assets/var';

.menu {
  width: 100%;
  height: 100%;
  display: flex;
  padding: 20px;

  .a-side {
    width: 480px;
    border-right: 1px solid #e4e8f3;
    padding-right: 10px;

    .a-side-title {
      display: flex;
      align-items: center;

      &::before {
        display: block;
        content: ' ';
        width: 4px;
        height: 12px;
        background-color: #575962;
        border-radius: 3px;
        margin-right: 6px;
      }
    }

    .a-side-add {
      cursor: pointer;
    }

    .a-side-input {
      margin: 15px 0;
    }

    :deep(.el-tree) {
      height: calc(100% - 80px);
      overflow: auto;
    }
  }

  .custom-tree-node {
    display: flex;
    flex: 1;
    justify-content: space-between;
    align-items: center;
    font-size: 14px;

    i {
      color: @breadcrumb-color;
      font-size: 14px;
    }

    .node-label {
      flex: 1;
    }
  }

  .header {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .content {
    width: 460px;
    padding: 0 30px;

    :deep(.el-form) {
      .el-select {
        width: 100%;
      }

      .el-input {
        width: 100%;
      }
    }

    .mg-10 {
      margin-top: 20px;
      margin-left: 100px;
    }
  }
}
</style>
